#include "main.h"

#define PWM0_H P14
#define PWM1_H P12
#define PWM2_H P10
#define PWM0_L P15
#define PWM1_L P13
#define PWM2_L P11


#define PWM1_CLK 20000
#define PWM1_PSCR_DIV 1
#define PWM1_COUNT_MAX (FOSC / PWM1_PSCR_DIV / PWM1_CLK / 2)

#define SIN_MAP_NUM 256UL
#define DEFAULT_RPM 60
#define POLE_NUM    7
#define TIMER_FREQ  ((DEFAULT_RPM * 6 * POLE_NUM) / 60 * SIN_MAP_NUM)
#define BRT         (65536 - FOSC / 12 / TIMER_FREQ)

#define APP_MODE_MAX 3
#define APP_SPEED_MAX 4

bit dir = 1;
uint8_t angle = 0;
uint8_t area = 0;
uint8_t PWM_Value = 0;

uint8_t mode = 0;
uint8_t speed = 1;

code uint16_t pwma_table[SIN_MAP_NUM]=
{823 ,825 ,827 ,828 ,830 ,832 ,834 ,836 ,838 ,840 ,841 ,843 ,845 ,847 ,849 ,850 ,852 ,854 ,855 ,857 ,859
 ,860 ,862 ,864 ,865 ,867 ,868 ,870 ,872 ,873 ,875 ,876 ,878 ,879 ,881 ,882 ,884 ,885 ,886 ,888 ,889 ,890 
 ,892 ,893 ,894 ,896 ,897 ,898 ,900 ,901 ,902 ,903 ,904 ,906 ,907 ,908 ,909 ,910 ,911 ,912 ,913 ,915 ,916 
 ,917 ,918 ,919 ,920 ,921 ,922 ,922 ,923 ,924 ,925 ,926 ,927 ,928 ,929 ,929 ,930 ,931 ,932 ,932 ,933 ,934 
 ,935 ,935 ,936 ,937 ,937 ,938 ,939 ,939 ,940 ,940 ,941 ,941 ,942 ,942 ,943 ,943 ,944 ,944 ,945 ,945 ,945 
 ,946 ,946 ,946 ,947 ,947 ,947 ,948 ,948 ,948 ,948 ,949 ,949 ,949 ,949 ,949 ,949 ,950 ,950 ,950 ,950 ,950 
 ,950 ,950 ,950 ,950 ,950 ,950 ,950 ,950 ,950 ,950 ,949 ,949 ,949 ,949 ,949 ,949 ,948 ,948 ,948 ,948 ,947 
 ,947 ,947 ,946 ,946 ,946 ,945 ,945 ,945 ,944 ,944 ,943 ,943 ,942 ,942 ,941 ,941 ,940 ,940 ,939 ,939 ,938 
 ,937 ,937 ,936 ,935 ,935 ,934 ,933 ,932 ,932 ,931 ,930 ,929 ,929 ,928 ,927 ,926 ,925 ,924 ,923 ,922 ,922 
 ,921 ,920 ,919 ,918 ,917 ,916 ,915 ,913 ,912 ,911 ,910 ,909 ,908 ,907 ,906 ,904 ,903 ,902 ,901 ,900 ,898 
 ,897 ,896 ,894 ,893 ,892 ,890 ,889 ,888 ,886 ,885 ,884 ,882 ,881 ,879 ,878 ,876 ,875 ,873 ,872 ,870 ,868 
 ,867 ,865 ,864 ,862 ,860 ,859 ,857 ,855 ,854 ,852 ,850 ,849 ,847 ,845 ,843 ,841 ,840 ,838 ,836 ,834 ,832
 ,830 ,828 ,827 ,825};

code uint16_t pwmb_table[SIN_MAP_NUM]=
{0 ,4 ,8 ,12 ,16 ,19 ,23 ,27 ,31 ,35 ,39 ,43 ,47 ,50 ,54 ,58 ,62 ,66 ,70 ,74 ,78 ,82 ,85 ,89 ,93 ,97 ,101 
,105 ,109 ,112 ,116 ,120 ,124 ,128 ,132 ,136 ,139 ,143 ,147 ,151 ,155 ,159 ,162 ,166 ,170 ,174 ,178 ,182 
,185 ,189 ,193 ,197 ,201 ,204 ,208 ,212 ,216 ,220 ,223 ,227 ,231 ,235 ,238 ,242 ,246 ,250 ,253 ,257 ,261 
,265 ,268 ,272 ,276 ,279 ,283 ,287 ,291 ,294 ,298 ,302 ,305 ,309 ,313 ,316 ,320 ,324 ,327 ,331 ,335 ,338 
,342 ,346 ,349 ,353 ,356 ,360 ,364 ,367 ,371 ,374 ,378 ,381 ,385 ,389 ,392 ,396 ,399 ,403 ,406 ,410 ,413 
,417 ,420 ,424 ,427 ,431 ,434 ,438 ,441 ,444 ,448 ,451 ,455 ,458 ,461 ,465 ,468 ,472 ,475 ,478 ,482 ,485 
,488 ,492 ,495 ,498 ,502 ,505 ,508 ,512 ,515 ,518 ,521 ,525 ,528 ,531 ,534 ,537 ,541 ,544 ,547 ,550 ,553 
,557 ,560 ,563 ,566 ,569 ,572 ,575 ,578 ,581 ,584 ,588 ,591 ,594 ,597 ,600 ,603 ,606 ,609 ,612 ,615 ,618 
,621 ,623 ,626 ,629 ,632 ,635 ,638 ,641 ,644 ,647 ,649 ,652 ,655 ,658 ,661 ,663 ,666 ,669 ,672 ,674 ,677 
,680 ,683 ,685 ,688 ,691 ,693 ,696 ,699 ,701 ,704 ,707 ,709 ,712 ,714 ,717 ,719 ,722 ,724 ,727 ,729 ,732 
,734 ,737 ,739 ,742 ,744 ,747 ,749 ,751 ,754 ,756 ,758 ,761 ,763 ,765 ,768 ,770 ,772 ,774 ,777 ,779 ,781 
,783 ,786 ,788 ,790 ,792 ,794 ,796 ,798 ,801 ,803 ,805 ,807 ,809 ,811 ,813 ,815 ,817 ,819 ,821};

xdata uint16_t pwma_map[SIN_MAP_NUM];
xdata uint16_t pwmb_map[SIN_MAP_NUM];

void bldc_gpio_init()
{
    PWM0_H = 1;
    PWM1_H = 1;
    PWM2_H = 1;
    PWM0_L = 0;
    PWM1_L = 0;
    PWM2_L = 0;
    
    P1M0 |= Bin(00111111);
    P1M1 &= ~Bin(00111111);

    P_SW2 = 0x80;
    P1SR &= ~Bin(00111111);
    P1DR &= ~Bin(00111111);
    P_SW2 = 0;
}

void pwm_init()
{
    P_SW2 = 0x80;
    
    PWM1_ENO = 0;
    PWM1_CCER1 = 0; //close channel
    PWM1_CCER2 = 0;
    PWM1_OISR = Bin(00010101);
    
    PWM1_CCMR1 = (0 << 7)|(0x6 << 4)|(1 << 3)|(0 << 2)|(0x0 << 0);  //set mode
    PWM1_CCMR2 = (0 << 7)|(0x6 << 4)|(1 << 3)|(0 << 2)|(0x0 << 0);
    PWM1_CCMR3 = (0 << 7)|(0x6 << 4)|(1 << 3)|(0 << 2)|(0x0 << 0);
    
    PWM1_PSCR = PWM1_PSCR_DIV-1;  //ser pscr
    
    PWM1_DTR = 4;  //set dead time
    
    PWM1_ARR = PWM1_COUNT_MAX-1;   //set arr
    
    PWM1_CCR1 = 0;  //set ccr
    PWM1_CCR2 = 0;
    PWM1_CCR3 = 0;
    
    PWM1_CCER1 = Bin(01110111); //out mode
    PWM1_CCER2 = Bin(00000111);
    
    PWM1_ENO = Bin(00111111);   //out enable
    
    PWM1_BKR = 0x80;    //disale bkr
    PWM1_CR1 = (0x3 << 5)|(1 << 0); //start counter
    
    PWM1_RCR = 0;
//    PWM1_IER = (1 << 0);
    
}

void tim_init()
{
	AUXR &= 0xBF;		//定时器时钟12T模式
	TMOD &= 0x0F;		//设置定时器模式
	TL1 = BRT;		//设置定时初始值
	TH1 = BRT>>8;		//设置定时初始值
	TF1 = 0;		//清除TF1标志
	TR1 = 1;		//定时器1开始计时
    
    ET1 = 1;
}

void bldc_init()
{
    bldc_gpio_init();
    pwm_init();
    tim_init();
    
    pwm_set(10);
}

//rpm -1000 - 1000 x10
void speed_set(int16_t rpm)
{
    uint16_t temp;
    
    if(rpm < 0)
    {
        temp = -rpm;
        dir = 0;
    }
    else
    {
        dir = 1;
        temp = rpm;
    }
    
    
    if(temp > 10000)
        temp = 10000;
    else if(temp < 3)
        temp = 3;
    
//    if(temp > 2000)
        pwm_set(temp / 120);
//    else
//        pwm_set(16);
    set_led1(temp);
    
    temp = (65536 - (FOSC / SIN_MAP_NUM / 12 * 100 / POLE_NUM) / temp);
    
    TL1 = temp;
    TH1 = temp>>8;
//    printf("rpm %d %u %bu\n", rpm, temp, PWM_Value);
}

//pwm: 0-64
void pwm_set(uint8_t pwm)
{
    uint16_t i;
    if(pwm > 64)
        pwm = 64;
    else if(pwm < 10)
        pwm = 10;
    
    if(pwm == PWM_Value)
        return;
    PWM_Value = pwm;
    
    for(i=0;i<SIN_MAP_NUM;i++)
    {
        pwma_map[i] = (pwma_table[i]*pwm)>>6;
        pwmb_map[i] = (pwmb_table[i]*pwm)>>6;
    }
}

void StepXL()
{
    switch(area)
    {
    case 0: //A -> C
        PWM1_CCR1 = pwma_map[angle];
        PWM1_CCR2 = pwmb_map[angle];
        PWM1_CCR3 = 0;
        break;
    case 1: //B -> C
        PWM1_CCR1 = pwmb_map[SIN_MAP_NUM-1-angle];
        PWM1_CCR2 = pwma_map[angle];
        PWM1_CCR3 = 0;
        break;
    case 2: //B -> A
        PWM1_CCR1 = 0;
        PWM1_CCR2 = pwma_map[angle];
        PWM1_CCR3 = pwmb_map[angle];
        break;
    case 3: //C -> A
        PWM1_CCR1 = 0;
        PWM1_CCR2 = pwmb_map[SIN_MAP_NUM-1-angle];
        PWM1_CCR3 = pwma_map[angle];
        break;
    case 4: //C -> B
        PWM1_CCR1 = pwmb_map[angle];
        PWM1_CCR2 = 0;
        PWM1_CCR3 = pwma_map[angle];
        break;
    case 5: //A -> B
        PWM1_CCR1 = pwma_map[angle];
        PWM1_CCR2 = 0;
        PWM1_CCR3 = pwmb_map[SIN_MAP_NUM-1-angle];
        break;
    }
}
#if 0
void PWM1_Isr() interrupt 26
{
    PWM1_SR1 = 0;
    
    angle++;
    if(angle==0)
    {
        area++;
        if(area>=6)
            area=0;
    }
    StepXL();
}
#endif

void TM1_Isr() interrupt 3
{
    if(dir)
    {
        angle++;
        if(angle==0)
        {
            if(area>=5)
                area=0;
            else
                area++;
        }
    }
    else
    {
        if(angle==0)
        {
            if(area)
                area--;
            else
                area=5;
        }
        angle--;
    }
    StepXL();
}

#define CYCLE_SPEED 2000L

void bldc_deal()
{
    static uint32_t time_last=0;
    static uint32_t mode0_time = CYCLE_SPEED;
    int32_t pwm;
    
    if(mode == 0)
    {
        if(timer >= time_last)
        {
            time_last = timer + 100;
            
            switch(speed)
            {
                case 0:speed_set(60);break;
                case 1:speed_set(240);break;
                case 2:speed_set(600);break;
                case 3:speed_set(1200);break;
            }
        }
    }
    else if(mode == 1)
    {
        if(timer >= time_last)
        {
            time_last = timer + 100;
            
            switch(speed)
            {
                case 0:speed_set(-60);break;
                case 1:speed_set(-240);break;
                case 2:speed_set(-600);break;
                case 3:speed_set(-1200);break;
            }
        }
    }
    else
    {
        if(timer >= time_last)
        {
            time_last = timer + 1;
            
            mode0_time++;
            pwm = mode0_time;
            pwm %= CYCLE_SPEED*4;
            if(pwm > CYCLE_SPEED*2)
                pwm = CYCLE_SPEED*4 - pwm;
            pwm -= CYCLE_SPEED;
            
            if(pwm%(CYCLE_SPEED/100) == 0)
                printf("rpm %ld pwm %bu\n", pwm, PWM_Value);
            
            speed_set(pwm*(speed+1)/4);
        }
    }
}

void key_deal()
{
	static uint32_t key_time=0;
    static uint8_t key_state=0;
    static bit key_low=0;
    
	static uint32_t key2_time=0;
    static uint8_t key2_state=0;
    static bit key2_low=0;
    
    if(timer != key_time)
    {
        key_time = timer;
        if(KEY1)
        {
            if(key_state<10)
                key_state++;
            else if(key_low)
            {
                key_low=0;
                LED2=0;
                
                mode++;
                if(mode >= APP_MODE_MAX)
                    mode=0;
            }
        }
        else
        {
            if(key_state)
                key_state--;
            else
            {
                key_low=1;
                LED2=1;
            }
        }
    }
    
    if(timer != key2_time)
    {
        key2_time = timer;
        if(KEY2)
        {
            if(key2_state<10)
                key2_state++;
            else if(key2_low)
            {
                key2_low=0;
                LED2=0;
                
                speed++;
                if(speed >= APP_SPEED_MAX)
                    speed=0;
            }
        }
        else
        {
            if(key2_state)
                key2_state--;
            else
            {
                key2_low=1;
                LED2=1;
            }
        }
    }
}